package service

import (
	"context"
	"fmt"
	"net"
	"strconv"
	"sync"
	"time"
)

type TcpService interface {
	Scan(ctx context.Context, ip string, ports []string, duration time.Duration) ([]int, []int, error)
}
type Port struct {
}

func NewPort() TcpService {
	return &Port{}
}
func (p *Port) Scan(ctx context.Context, ip string, ports []string, duration time.Duration) ([]int, []int, error) {
	open := make([]int, 0)
	cls := make([]int, 0)
	wg := &sync.WaitGroup{}
	mutex := &sync.Mutex{}
	for _, port := range ports {
		wg.Add(1)
		go func(port string) {
			p, _ := strconv.Atoi(port)
			ok := isOpen(ctx, ip, p, duration)
			if ok {
				mutex.Lock()
				open = append(open, p)
				mutex.Unlock()
			} else {
				mutex.Lock()
				cls = append(cls, p)
				mutex.Unlock()
			}
			wg.Done()
		}(port)
	}
	wg.Wait()
	return open, cls, nil
}

func isOpen(ctx context.Context, host string, port int, timeout time.Duration) bool {
	//ctx, cancel := context.WithTimeout(ctx, timeout)
	//defer cancel()
	conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), timeout)
	if err == nil {
		_ = conn.Close()
		return true
	}
	//} else if errors.Is(err, context.Canceled) {
	//	return false
	//} else if errors.Is(err, context.DeadlineExceeded) {
	//	return false
	//}
	return false
}
